package fem2;

import inf.jlinalg.IMatrix;
import inf.jlinalg.IVector;
import fem2.element.StructuralElement;
import fem2.enu.PropertyName;
import fem2.enu.State;
import fem2.enu.StressType;

/**
 * Abstract material model for structural elements
 * 
 * @author hbui
 * 
 */
public abstract class MaterialModel extends ElementManager implements StrategyPart {

	/*****************************************
	 * Constructor & get/set
	 ****************************************/
	/**
	 * copy constructor
	 */
	public MaterialModel(MaterialModel mm) {
		this(mm.getDensity(), mm.getSectionProperty(), mm.getState());
	}

	/**
	 * constructor
	 * 
	 * @param rho
	 * @param thickness
	 * @param ss
	 */
	public MaterialModel(double rho, double thickness, State ss) {
		setDensity(rho);
		this.ss = ss;
		switch (ss) {
		case PLANE_STRAIN:
			setSectionProperty(thickness);
			break;
		case PLANE_STRESS:
			setSectionProperty(thickness);
			break;
		case THREE_DIMENSIONAL:
			if (thickness != 1.0)
				Debugger.warn("MaterialModel: thickness for 3d material must be 1.0. Setting thickness to 1.0");
			setSectionProperty(1.0);
			break;
		case ONE_DIMENSIONAL:
			Debugger.warn("MaterialModel: thickness in 1d case is cross section area");
			setSectionProperty(thickness);
			break;
		default:
			throw new Error("invalid stress state");
		}
	}

	private double density = 1.0;
	private double thickness = 1.0;
	private State ss;

	/**
	 * 
	 * @return the mass density
	 */
	public double getDensity() {
		return density;
	}

	/**
	 * set the mass density
	 * 
	 * @param rho
	 */
	protected void setDensity(double rho) {
		this.density = rho;
	}

	/**
	 * set thickness for material. For 3d model, thickness is 1.0
	 * 
	 * @param t
	 */
	protected void setSectionProperty(double t) {
		thickness = t;
	}

	/**
	 * 
	 * @return section property is thickness in 2d. In 3d, section property is
	 *         1.0. In 1d, section property is cross section area
	 */
	public double getSectionProperty() {
		return thickness;
	}

	/**
	 * 
	 * @return the state (plane strain, plane stress, 3d, ...)
	 */
	public State getState() {
		return this.ss;
	}

	/**
	 * get property of the material
	 * 
	 * @param name
	 * @return
	 */
	public double getMaterialProperty(PropertyName name) {
		throw new NotImplementedError();
	}

	/**
	 * 
	 * @param e
	 *            the respective element associated with this model
	 * @param k
	 *            gp index
	 * @return the constitutive matrix associated with the Gauss point k.
	 * 
	 *         Note for developer: for selective reduced integration scheme the
	 *         Gauss point is more than standard. This function must understand
	 *         the Gauss point index correctly
	 */
	public abstract IMatrix getConstitutiveMatrix(Element e, int k);

	/**
	 * get the real stress of an element. In case the algorithm requires element
	 * to work on algorithmic stress (like implicit/explicit), the material
	 * model will manage the real stress and return when needed. Note that the
	 * element manage algorithmic stress only.<br>
	 * Override this method if the algorithmic stress are not real stress (i.e
	 * implicit/explicit )
	 * 
	 * @param e
	 * @param k
	 * @return
	 */
	public IVector getStress(Element e, int k, StressType type) {
		switch (type) {
		case CAUCHY_STRESS:
			return ((StructuralElement) e).getStress(k);
		case ALGORITHMIC_STRESS:
			return ((StructuralElement) e).getStress(k);
		default:
			throw new NotImplementedError();
		}
	}

}
